package cn.buddha.jesj.thread;

import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * @ClassName FutureTest
 * @Description TODO
 * @Author shihao
 * @Date 2021/8/28 0028 17:50
 * @Version 1.0
 **/
@Slf4j
public class FutureTest {

    public static final Long THREAD_FIRST_SLEEP_TIME = 8000L;
    public static final Long THREAD_SECOND_SLEEP_TIME = 2000L;
    public static final Long THREAD_THREE_SLEEP_TIME = 10000L;

    public static void main(String[] args) {
//        executorServiceTest();

        completionServiceTest();
    }

    public static void completionServiceTest() {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        CompletionService<String> completionService = new ExecutorCompletionService<>(executorService);

        List<Future<String>> futureList = new ArrayList<>(3);

        futureList.add(
                completionService.submit(new Callable<String>() {
                    @Override
                    public String call() throws Exception {
                        log.info("Thread 1 starting ...");
                        Thread.sleep(THREAD_FIRST_SLEEP_TIME);
                        return "Thread-1";
                    }
                })
        );

        futureList.add(
                completionService.submit(new Callable<String>() {
                    @Override
                    public String call() throws Exception {
                        log.info("Thread 2 starting ...");
                        Thread.sleep(THREAD_SECOND_SLEEP_TIME);
                        return "Thread-2";
                    }
                })
        );

        futureList.add(
                completionService.submit(new Callable<String>() {
                    @Override
                    public String call() throws Exception {
                        log.info("Thread 3 starting ...");
                        Thread.sleep(THREAD_THREE_SLEEP_TIME);
                        return "Thread-3";
                    }
                })
        );

        long startTime = System.currentTimeMillis();
        for (Future<String> future : futureList) {
            try {
                log.info(completionService.take().get());
                /**
                 * 当从 {@link ExecutorCompletionService#completionQueue} 队列中取出第一个元素时，就直接 break。
                 * 也就意味着，只取第一个，其他的就不管了。
                 */
                break;
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        }

        futureList.forEach(future -> {
            // 当上面的 for 循环结束时，也就是说只取其中一个 异步任务的结果，然后，其他的异步线程任务就取消掉，没有执行的必要了。
            future.cancel(true);
        });
        System.err.println("耗时: " + (System.currentTimeMillis() - startTime));
        executorService.shutdown();
    }

    public static void executorServiceTest() {
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        List<Future<String>> futureList = new ArrayList<>(3);

        futureList.add(
                executorService.submit(() -> {
                    log.info("Thread 1 starting ...");
                    Thread.sleep(THREAD_FIRST_SLEEP_TIME);
                    return "Thread-1";
                })
        );

        futureList.add(
                executorService.submit(() -> {
                    log.info("Thread 2 starting ...");
                    Thread.sleep(THREAD_SECOND_SLEEP_TIME);
                    return "Thread-2";
                })
        );

        futureList.add(
                executorService.submit(() -> {
                    log.info("Thread 3 starting ...");
                    Thread.sleep(THREAD_THREE_SLEEP_TIME);
                    return "Thread-3";
                })
        );

        long startTime = System.currentTimeMillis();
        futureList.forEach(future -> {
            try {
                log.info(future.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        });
        System.err.println("耗时: " + (System.currentTimeMillis() - startTime));
        executorService.shutdown();
    }

}
